
                /*********************************************
                **                                          **
                **                                          **
                **                newCommR                  **
                **           single shared leader           **
                **                                          **
                *********************************************/
                /*********************************************
                **                                          **
                **         Author Jean-Marc Adamo           **
                **       Copyright (C) 1997-2008 JMA        **
                *********************************************/



/*
** execute with 6 processes
*/

#include "arch.h"
#include "A.utilities"

//user program

Coll_id cid1, cid2, cid3, cid4, cid5, cid6, cid7, cid8, cid9, cid10;

//on most homogenous systems, explicit setting 
//won't be necessary (try commenting the
//setting lines, you should get the same values
//for all cid).
void init(int, char **){
   cid1.set();
   cid2.set();
   cid3.set();
   cid4.set();
   cid5.set();
   cid6.set();
   cid7.set();
   cid8.set();
   cid9.set();
   cid10.set();
   fprintf(Sdf::trace, "node%d: cid1=%d, cid2=%d, cid3=%d, cid4=%d, cid5=%d, cid6=%d, cid7=%d, cid8=%d, cid9=%d, cid10=%d\n",
           Sdf::PROC_ID,
           cid1.get(), cid2.get(), cid3.get(), cid4.get(), cid5.get(),
           cid6.get(), cid7.get(), cid8.get(), cid9.get(), cid10.get());
   fflush(Sdf::trace);
}

class Proc: public S_Thread{

   public:
        int pid;
        int step;

        Proc(int p, int s)
            : S_Thread((Smf0_ptr)&Proc::body){
                  pid = p; 
                  step = s; 
        }

        void body(){
               fprintf(Sdf::trace, "node %d, pid:%d at start\n",
                       Sdf::PROC_ID, pid);
               fflush(Sdf::trace);
               int i;
               for(i = 0; i < 4; i++){
                   fprintf(Sdf::trace, "node %d, pid:%d, step:%d, i=%d\n",
                           Sdf::PROC_ID, pid, step, i);
                   fflush(Sdf::trace);

                   reschedule();
               }

               if(step<1){
                   if(pid==1){
/*****/
                      fprintf(Sdf::trace, "node %d, pid:%d, step:%d, *1*\n", 
                              Sdf::PROC_ID, pid, step);
                      fflush(Sdf::trace);

                      int ranks1[2] = {1, 5};
                      Group *incl_grp1 = Sdf::incl(Sdf::COMML_WORLD, 2, ranks1);
                      int incl_grp1_size = incl_grp1->size();
                      int incl_grp1_rank = incl_grp1->rank();

                      int ranks2[2] = {3, 5};
                      Group *incl_grp2 = Sdf::incl(Sdf::COMML_WORLD, 2, ranks2);
                      int incl_grp2_size = incl_grp2->size();
                      int incl_grp2_rank = incl_grp2->rank();

                      int ranks3[3] = {1, 3, 5};
                      Group *super_grp = Sdf::incl(Sdf::COMML_WORLD, 3, ranks3);
                      int super_grp_size = super_grp->size();
                      int super_grp_rank = super_grp->rank();

                      fprintf(Sdf::trace, "node %d, pid:%d, step:%d, *2*, size1 =%d, size2 =%d, size3 =%d, rank1 =%d, rank2 =%d, rank3 =%d\n", 
                              Sdf::PROC_ID, pid, step,
                              incl_grp1_size, incl_grp2_size, super_grp_size,
                              incl_grp1_rank, incl_grp2_rank, super_grp_rank);
                      fflush(Sdf::trace);

                      CommL *comm1 = incl_grp1->commit(cid1, Sdf::COMML_WORLD);

                      CommL *comm2 = incl_grp2->commit(cid2, Sdf::COMML_WORLD);

                      CommL *super_comm = super_grp->commit(cid3, Sdf::COMML_WORLD);

                      fprintf(Sdf::trace, "node %d, pid:%d, step:%d, *3*, comm1=%d, comm2=%d, super_comm=%d, size1=%d, size2=%d, size3=%d\n", 
                              Sdf::PROC_ID, pid, step,
                              comm1, comm2, super_comm,
                              comm1->size(), comm2->size(), super_comm->size());
                      fflush(Sdf::trace);

                      int cw_rank = Sdf::COMML_WORLD->rank();

                      if(cw_rank == 1 || cw_rank == 3 ||cw_rank == 5){
                        CommR *commr = Sdf::newCommR(cid4, comm1, comm2, super_comm);
                        int *rem_ranks;
                        int *loc_ranks;
                        rem_ranks = commr->get_remote_CommL()->get_world_ranks();
                        loc_ranks = commr->get_local_CommL()->get_world_ranks();

                        int i;
                        int size = commr->get_local_CommL()->size();
                        fprintf(Sdf::trace, "node %d, pid:%d, step:%d, *4*, local  CommL, size=%d\n", 
                                Sdf::PROC_ID, pid, step, size);
                        for(i=0; i<size; i++)
                           fprintf(Sdf::trace, "node %d,                        loc_ranks[%d]=%d\n", 
                                Sdf::PROC_ID, i, loc_ranks[i]);

                                 size = commr->get_remote_CommL()->size();
                        fprintf(Sdf::trace, "node %d, pid:%d, step:%d, *5*, remote CommL, size=%d\n", 
                                Sdf::PROC_ID, pid, step, size);
                        for(i=0; i<size; i++)
                           fprintf(Sdf::trace, "node %d,                        rem_ranks[%d]=%d\n", 
                                   Sdf::PROC_ID, i, rem_ranks[i]);
                        fflush(Sdf::trace);

                        delete []rem_ranks;
                        delete []loc_ranks;

                        CommL *merge_comm = commr->merge(cid5, Sdf::N);
                                         //to merge in the order comm1, comm2
                                         //switch to Sdf::C for merging in the order comm2, comm1
                        int *ranks = merge_comm->get_world_ranks();
                        size = merge_comm->size();
                        fprintf(Sdf::trace, "node %d, pid:%d, step:%d, *6*, merge_comm, size=%d\n", 
                                Sdf::PROC_ID, pid, step, size);
                        for(i=0; i<size; i++)
                           fprintf(Sdf::trace, "node %d,                            ranks[%d]=%d\n", 
                                   Sdf::PROC_ID, i, ranks[i]);
                        fflush(Sdf::trace);

                        delete comm1;
                        delete comm2;
                        delete super_comm;
                        delete commr;
                        delete merge_comm;
                        delete []ranks;
                      }

                      fprintf(Sdf::trace, "pid:%d, step:%d, *7*\n", 
                              Sdf::PROC_ID, pid, step);
                      fflush(Sdf::trace);

                      Proc *proc1 = new Proc(pid*10 + 1, step+1);
                      Proc *proc2 = new Proc(pid*10 + 2, step+1);
                      S_Thread *proc_tabl[2] = {proc1, proc2};
                      int pri[2] = {1, 1};
                      par(2, proc_tabl, pri);
                      delete proc1;
                      delete proc2;

                      fprintf(Sdf::trace, "pid:%d, step:%d, *8*\n", 
                              Sdf::PROC_ID, pid, step);
                      fflush(Sdf::trace);
/*****/
                   }else{
/*****/
                      fprintf(Sdf::trace, "node %d, pid:%d, step:%d, *1*\n", 
                              Sdf::PROC_ID, pid, step);
                      fflush(Sdf::trace);

                      int ranks1[2] = {0, 4};
                      Group *incl_grp1 = Sdf::incl(Sdf::COMML_WORLD, 2, ranks1);
                      int incl_grp1_size = incl_grp1->size();
                      int incl_grp1_rank = incl_grp1->rank();

                      int ranks2[2] = {2, 4};
                      Group *incl_grp2 = Sdf::incl(Sdf::COMML_WORLD, 2, ranks2);
                      int incl_grp2_size = incl_grp2->size();
                      int incl_grp2_rank = incl_grp2->rank();

                      int ranks3[3] = {0, 2, 4};
                      Group *super_grp = Sdf::incl(Sdf::COMML_WORLD, 3, ranks3);
                      int super_grp_size = super_grp->size();
                      int super_grp_rank = super_grp->rank();

                      fprintf(Sdf::trace, "node %d, pid:%d, step:%d, *2*, size1 =%d, size2 =%d, size3 =%d, rank1 =%d, rank2 =%d, rank3 =%d\n", 
                              Sdf::PROC_ID, pid, step, 
                              incl_grp1_size, incl_grp2_size, super_grp_size,
                              incl_grp1_rank, incl_grp2_rank, super_grp_rank);
                      fflush(Sdf::trace);

                      CommL *comm1 = incl_grp1->commit(cid6, Sdf::COMML_WORLD);

                      CommL *comm2 = incl_grp2->commit(cid7, Sdf::COMML_WORLD);

                      CommL *super_comm = super_grp->commit(cid8, Sdf::COMML_WORLD);

                      fprintf(Sdf::trace, "node %d, pid:%d, step:%d, *3*, comm1=%d, comm2=%d, super_comm=%d, size1=%d, size2=%d, size3=%d\n", 
                              Sdf::PROC_ID, pid, step,
                              comm1, comm2, super_comm,
                              comm1->size(), comm2->size(), super_comm->size());
                      fflush(Sdf::trace);

                      int cw_rank = Sdf::COMML_WORLD->rank();

                      if(cw_rank == 0 || cw_rank == 2 ||cw_rank == 4){
                        CommR *commr = Sdf::newCommR(cid9, comm1, comm2, super_comm);
                        int *rem_ranks;
                        int *loc_ranks;
                        rem_ranks = commr->get_remote_CommL()->get_world_ranks();
                        loc_ranks = commr->get_local_CommL()->get_world_ranks();

                        int i;
                        int size = commr->get_local_CommL()->size();
                        fprintf(Sdf::trace, "node %d, pid:%d, step:%d, *4*, local  CommL, size=%d\n", 
                                Sdf::PROC_ID, pid, step, size);
                        for(i=0; i<size; i++)
                           fprintf(Sdf::trace, "node %d,                        loc_ranks[%d]=%d\n", 
                                Sdf::PROC_ID, i, loc_ranks[i]);

                        size = commr->get_remote_CommL()->size();
                        fprintf(Sdf::trace, "node %d, pid:%d, step:%d, *5*, remote CommL, size=%d\n", 
                                Sdf::PROC_ID, pid, step, size);
                        for(i=0; i<size; i++)
                           fprintf(Sdf::trace, "node %d,                        rem_ranks[%d]=%d\n", 
                                   Sdf::PROC_ID, i, rem_ranks[i]);
                        fflush(Sdf::trace);

                        delete []rem_ranks;
                        delete []loc_ranks;

                        CommL *merge_comm = commr->merge(cid10, Sdf::N);
                                         //to merge in the order comm1, comm2
                                         //switch to Sdf::C for merging in the order comm2, comm1
                        int *ranks = merge_comm->get_world_ranks();
                        size = merge_comm->size();
                        fprintf(Sdf::trace, "node %d, pid:%d, step:%d, *6*, merge_comm, size=%d\n", 
                                Sdf::PROC_ID, pid, step, size);
                        for(i=0; i<size; i++)
                           fprintf(Sdf::trace, "node %d,                            ranks[%d]=%d\n", 
                                   Sdf::PROC_ID, i, ranks[i]);
                        fflush(Sdf::trace);

                        delete comm1;
                        delete comm2;
                        delete super_comm;
                        delete commr;
                        delete merge_comm;
                        delete []ranks;
                      }

                      fprintf(Sdf::trace, "pid:%d, step:%d, *7*\n", 
                              Sdf::PROC_ID, pid, step);
                      fflush(Sdf::trace);

                      Proc *proc1 = new Proc(pid*10 + 1, step+1);
                      Proc *proc2 = new Proc(pid*10 + 2, step+1);
                      S_Thread *proc_tabl[2] = {proc1, proc2};
                      int pri[2] = {1, 1};
                      par(2, proc_tabl, pri);
                      delete proc1;
                      delete proc2;

                      fprintf(Sdf::trace, "pid:%d, step:%d, *8*\n", 
                              Sdf::PROC_ID, pid, step);
                      fflush(Sdf::trace);
/*****/
                   }
               }

               fprintf(Sdf::trace, "node %d, pid:%d the end at step %d\n",
                        Sdf::PROC_ID, pid, step);
               fflush(Sdf::trace);
        }
};

class Root_proc: public Thread{

   public:

        Root_proc()
                : Thread((Tmf0_ptr)&Root_proc::body){}

        void body(){

                fprintf(Sdf::trace, "node %d, in Root_proc::body1\n", Sdf::PROC_ID);
                fflush(Sdf::trace);

                Proc *proc1;
                Proc *proc2;
                proc1 = new Proc(1, 0);
                proc2 = new Proc(2, 0);
                fprintf(Sdf::trace, "node %d, in Root_proc::body2\n", Sdf::PROC_ID);
                fflush(Sdf::trace);
                S_Thread *proc_tabl[2] = {proc1, proc2};
                int pri[2] = {1, 1};
                par(2, proc_tabl, pri);

                fprintf(Sdf::trace, "node %d, in Root_proc::body4\n", Sdf::PROC_ID);
                fflush(Sdf::trace);

                delete proc1;
                delete proc2;
        }
};
//end of user program

MAIN(Root_proc, init, Sdf::empty, Sdf::empty)

